package com.vardhan.teja.dashclock.gmailextension;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import android.accounts.Account;
import android.accounts.AccountManager;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.database.SQLException;
import android.preference.PreferenceManager;
import android.provider.OpenableColumns;
import android.util.Log;
import android.widget.SlidingDrawer;

import com.google.android.apps.dashclock.api.DashClockExtension;
import com.google.android.apps.dashclock.api.ExtensionData;

/**
 * @author TejaVardhan
 *
 */
public class CustomGmail extends DashClockExtension
{
	public static final String PREF_ACCOUNTS = "pref_gmail_accounts";
    public static final String PREF_PERSISTENT = "pref_gmail_persistent";

    private static final String ACCOUNT_TYPE_GOOGLE = "com.google";
    
    @Override
    protected void onInitialize(boolean isReconnect) {
        super.onInitialize(isReconnect);
        if (!isReconnect) {
        	
            createUris();
        }
    }
    
    private void createUris(){
    	Set<String> selectedAccounts = getSelectedAccounts(this);
        List<String> selectedUris = new ArrayList<String>();
        for (String account : selectedAccounts) {	
        	// Get the URI's of selected labels for an account
        	selectedUris.addAll(getSelectedUris(account));	  
        }
        String[] uris = new String[selectedUris.size()];
        selectedUris.toArray(uris);
         
        addWatchContentUris(uris);
    }
    
	@Override
	protected void onUpdateData(int reason)
	{
		//Update Uri's when settings are changed
		if(reason == CustomGmail.UPDATE_REASON_SETTINGS_CHANGED)
		{
			createUris();
		}
		
		//Update widget content when changes in registered Uri's are detected
		if(reason == CustomGmail.UPDATE_REASON_CONTENT_CHANGED || reason == CustomGmail.UPDATE_REASON_SETTINGS_CHANGED)
		{
			Set<String> selectedAccounts = getSelectedAccounts(this);
			int unread = 0;
			Map<String,Integer> unreadOfAccount = new HashMap<String, Integer>();
			Map<String,Map<String,Integer>> unreadPerAccount = new HashMap<String,Map<String,Integer>>();

			for(String account : selectedAccounts)
			{
				Set<String> selectedLabels = getSelectedLabels(account,this);
				Cursor cursor = openLabelsCursor(account);

				if (cursor == null || cursor.isAfterLast()) {
					if (cursor != null) {
						cursor.close();
					}
					continue;
				}

				while (cursor.moveToNext()) {
					if (selectedLabels.contains(cursor.getString(LabelsQuery.CANONICAL_NAME)) || selectedLabels.contains(cursor.getString(LabelsQuery.NAME))) {
						int unreadThisLabel = cursor.getInt(LabelsQuery.NUM_UNREAD_CONVERSATIONS);
						Map<String,Integer> unreadPerLabel = unreadPerAccount.get(account);
						if(unreadThisLabel > 0)
						{
							if(unreadPerLabel == null)
							{
								unreadPerLabel = new HashMap<String, Integer>();
							}
							unreadPerLabel.put(cursor.getString(LabelsQuery.NAME), unreadThisLabel);
							unreadPerAccount.put(account, unreadPerLabel);
							unread += unreadThisLabel;
							if(!unreadOfAccount.containsKey(account))
							{
								unreadOfAccount.put(account, unreadThisLabel);
							}
							else
							{
								unreadOfAccount.put(account, unreadOfAccount.get(account) + unreadThisLabel);
							}
						}

					}
				}

				cursor.close();
			}
			StringBuilder body = new StringBuilder();
			if(unread > 0)
			{

				for(String account : unreadPerAccount.keySet())
				{
					if (body.length() > 0) {
						body.append("\n");
					}

					if(selectedAccounts.size() > 1)
					{
						body.append(account).append(" (").append(unreadOfAccount.get(account)).append(") : ");
					}

					Map<String,Integer> unreadPerLabel = unreadPerAccount.get(account);
					for(String label : unreadPerLabel.keySet())
					{
						body.append(label).append(" (").append(unreadPerLabel.get(label)).append(") ");
					}
				}

			}

			publishUpdate(new ExtensionData()
			.visible(unread > 0)
			.status(Integer.toString(unread))
			.expandedTitle(getResources().getQuantityString(
					R.plurals.gmail_unread, unread, unread))
					.icon(R.drawable.ic_extension_gmail_custom)
					.expandedBody(body.toString())
					.clickIntent(new Intent(Intent.ACTION_MAIN)
					.setPackage("com.google.android.gm")
					.addCategory(Intent.CATEGORY_LAUNCHER)));
		}
		
	}
	
	
	
	/**
	 * Gets the Uri's of selected labels for an account
	 * @param account
	 * @return
	 */
	private Set<String> getSelectedUris(String account)
	{
		Cursor cursor = openLabelsCursor(account);
            Set<String> labels = getSelectedLabels(account,this);
            
            Set<String> selectedUris = new HashSet<String>();
            
            
            if (cursor == null || cursor.isAfterLast()) {
                
                if (cursor != null) {
                    cursor.close();
                }
            }

            while (cursor.moveToNext()) {
            	
            	// Check to see if the label is selected by the user.
                if (labels.contains(cursor.getString(LabelsQuery.CANONICAL_NAME)) || labels.contains(cursor.getString(LabelsQuery.NAME))) {
                    selectedUris.add(cursor.getString(LabelsQuery.URI));
                }
            }
            
            cursor.close();
            
            return selectedUris;
	}
	
	
	/**
	 * Gets the account names of all the gmail accounts present in a user device. 
	 * @param context
	 * @return
	 */
	static String[] getAllAccountNames(Context context) {
        final Account[] accounts = AccountManager.get(context).getAccountsByType(
                CustomGmail.ACCOUNT_TYPE_GOOGLE);
        final String[] accountNames = new String[accounts.length];
        for (int i = 0; i < accounts.length; i++) {
            accountNames[i] = accounts[i].name;
        }
        return accountNames;
    }
    
	/**
	 * Get the Canonical name of Inbox for an account. This is taken as defaultlabel and used when
	 * no labels are selected for account by user.
	 * @return 
	 */
    static String[] getDefaultLabels()	{
    	final String[] labelNames = new String[2];
    	labelNames[0] = GmailContract.Labels.LabelCanonicalNames.CANONICAL_NAME_INBOX;
    	
    	return labelNames;
    }
    
    
    /**
     * Get the selected accounts for which unread count is to be displayed. By default all accounts are
     * selected if the user doesn't select them. 
     * @param context
     * @return
     */
    protected static Set<String> getSelectedAccounts(Context context) {
        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
        final String[] accounts = CustomGmail.getAllAccountNames(context);
        Set<String> allAccountsSet = new HashSet<String>();
        allAccountsSet.addAll(Arrays.asList(accounts));
        return sp.getStringSet(PREF_ACCOUNTS, allAccountsSet);
    }
    
    
    
    /**
     * Gets the Selected labels for an account. The selected Labels are stored in sharedpreferences with the 
     * key as the account name.
     * @param account
     * @param context
     * @return
     */
    protected static Set<String> getSelectedLabels(String account, Context context)	{
    	SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
    	Set<String> defaultLabels = new HashSet<String>();
    	defaultLabels.addAll(Arrays.asList(getDefaultLabels()));
    	return sp.getStringSet(account, defaultLabels);
    }
    
    private Cursor openLabelsCursor(String account) {
        try {
            return getContentResolver().query(
                    GmailContract.Labels.getLabelsUri(account),
                    LabelsQuery.PROJECTION,
                    null, // NOTE: the Labels API doesn't allow selections here
                    null,
                    null);

        } catch (SecurityException e) {
            // From developer console: "Permission Denial: opening provider com.google.android.gsf..
            return null;

        } catch (SQLException e) {
            // From developer console: "SQLiteException: no such table: labels"
            return null;
        }
    }
    
	
	protected interface LabelsQuery {
        String[] PROJECTION = {
                GmailContract.Labels.NUM_UNREAD_CONVERSATIONS,
                GmailContract.Labels.URI,
                GmailContract.Labels.CANONICAL_NAME,
                GmailContract.Labels.NAME,
        };

        int NUM_UNREAD_CONVERSATIONS = 0;
        int URI = 1;
        int CANONICAL_NAME = 2;
        int NAME = 3;
    }
}
